package com.gzz.orchid.common.boot.mybatis.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.PreparedStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * 数据源切换拦截器
 *
 * @author G-m
 */
@Slf4j
@Intercepts({
        //        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class}),
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
        @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
        @Signature(type = ParameterHandler.class, method = "getParameterObject", args = {MappedStatement.class, Object.class})
})
public class DataSourceInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation inv) throws Throwable {
        log.debug("进入了注解 DataSourceInterceptor。。。。。。。。。。。。");
        boolean sync = TransactionSynchronizationManager.isSynchronizationActive();
        log.info("异步处理标志： {}", sync);
        if (!sync) {
            Object[] args = inv.getArgs();
            log.info("Args 长度：" + args.length);
            for (Object obj : args) {
                System.out.println(obj);
            }
            MappedStatement mappedStatement = (MappedStatement) args[0];
            String msId = mappedStatement.getId();
            BoundSql boundSql = mappedStatement.getSqlSource().getBoundSql(args[1]);
            String sql = boundSql.getSql().toLowerCase(Locale.CHINA);
            //            log.info("MSID: {}, CommandType: {}, 将要执行的SQL: {}",msId, mappedStatement.getSqlCommandType().name(),sql);
            //            // 读方法, !selectKey 为自增id查询主键(SELECT LAST_INSERT_ID() )方法，使用主库
            //            if (mappedStatement.getSqlCommandType().equals(SqlCommandType.SELECT)
            //                    && msId.contains(SelectKeyGenerator.SELECT_KEY_SUFFIX) == false) {
            //                log.info("");
            //            } else {
            //
            //            }
            log.info("MSID[{}]", msId);
            log.info("SELECT_KEY_SUFFIX [{}] ", SelectKeyGenerator.SELECT_KEY_SUFFIX);
            log.info("SqlCommandType [{}]", mappedStatement.getSqlCommandType().name());
            log.info("执行SQL [{}]", sql);
        }
        return inv.proceed();
    }
    private Object doQuery(Invocation inv) throws Exception{
        Executor executor = (Executor) inv.getTarget();
        MappedStatement ms = (MappedStatement) inv.getArgs()[0];
        Object parameter = inv.getArgs()[1];
        RowBounds rowBounds = (RowBounds) inv.getArgs()[2];
        //
        if(parameter instanceof Map){
            MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameter;
            if(paramMap.containsKey("et")){
                parameter = paramMap.get("et");
            }
        }
        // 直接执行Query，不用proceed()方法
        return executor.query(ms, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
    }

    private Object changeBoundSql(Invocation inv) throws Exception{
        StatementHandler sh = (StatementHandler) inv.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(sh);
        PreparedStatementHandler psh = (PreparedStatementHandler) metaObject.getValue("delegate");
        String orighinalSql = (String) metaObject.getValue("delegate.boundSql.sql");
        metaObject.setValue("delegate.boundSql.sql", orighinalSql +" and version=?");
        return inv.proceed();
    }
    private Object doSetParameters(Invocation inv) throws Exception{
        ParameterHandler ph = (ParameterHandler) inv.getTarget();
        PreparedStatement ps = (PreparedStatement) inv.getArgs()[0];
        MetaObject metaObject = SystemMetaObject.forObject(ph);
        BoundSql boundSql = (BoundSql) metaObject.getValue("boundSql");

        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        boolean hasTenantId = false;
        for (ParameterMapping parameterMapping : parameterMappings) {
            if("tenantId".equals(parameterMapping.getProperty())){
                hasTenantId = true;
            }
        }
        //添加参数
        if(!hasTenantId){
            Configuration config = (Configuration) metaObject.getValue("configuration");
            ParameterMapping tenantIdMapping = new ParameterMapping.Builder(config, "tenantId", Integer.class).build();
            parameterMappings.add(tenantIdMapping);
        }
        ph.setParameters(ps);
        return  null;
    }
}
